home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / src / exampleCode / irix / playEngine / playEngine.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-02  |  24.3 KB  |  836 lines

  1. /*
  2.  * Copyright (C) 1994, Silicon Graphics, Inc.
  3.  * All Rights Reserved.
  4.  *
  5.  * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
  6.  * the contents of this file may not be disclosed to third parties, copied or
  7.  * duplicated in any form, in whole or in part, without the prior written
  8.  * permission of Silicon Graphics, Inc.
  9.  *
  10.  * RESTRICTED RIGHTS LEGEND:
  11.  * Use, duplication or disclosure by the Government is subject to restrictions
  12.  * as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
  13.  * and Computer Software clause at DFARS 252.227-7013, and/or in similar or
  14.  * successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
  15.  * rights reserved under the Copyright Laws of the United States.
  16.  */
  17. /*----------------------------------------------------------------------
  18.  * $Id: PlayEngine.c,v 2.7 92/07/17 16:43:44 carlson Exp $
  19.  *
  20.  * PlayEngine.c        This file contains all the routines for accessing
  21.  *             setting up and communicating with the play engine.
  22.  *
  23.  * The purpose of the play engine is to provide a method of running
  24.  * an audio track at a high priority so that it won't be interrupted
  25.  * by normal system activity, including windows being moved around
  26.  * and background system deamon activity.
  27.  *
  28.  * The technique used is to sproc into two processes where one process
  29.  * (the play engine) raises its priority real high and the other process
  30.  * (the application) remains at the user's privilege level.  This
  31.  * procedure requires the executable to be owned by root and the set-UID
  32.  * bit to be set.
  33.  *
  34.  * This set of routines will work with or without the use of system
  35.  * semaphores.  A #define indicates how it should be compiled.
  36.  *
  37.  * MISCELLANEOUS:
  38.  *    Notice that there are no references to 'errno'.  These
  39.  *    references have been changed to call the function 'oserror'.
  40.  *    This is because, when working with multiple processes, the
  41.  *    value for errno can be set by either process and this could
  42.  *    cause confusing results.  Calling 'oserror' guarantees the
  43.  *    process of getting "its" last value of 'errno'.
  44.  *
  45.  *    As of IRIX 5.1, 'errno' is actually #defined to call
  46.  *    'oserror'.  Either way, it is a good idea to read 'oserror'
  47.  *    or 'errno' into a local variable and then process its
  48.  *    contents rather than keep checking the value in 'errno'.
  49.  *
  50.  * Function Description:
  51.  *    This is a short description of each of the functions.  For
  52.  *    a more complete description, read the documentation preceding
  53.  *    each function.
  54.  *
  55.  *    Static Functions:
  56.  *    -----------------
  57.  *    semOp        Perform a semaphore operation.  Handles
  58.  *            situations where signals interrupt the wait
  59.  *            or where the parent dies.
  60.  *
  61.  *    other_process    This is the routine that is referred to in
  62.  *            sproc call and is the "main" for the "play
  63.  *            engine" process.  It contains an "infinite"
  64.  *            loop that waits for commands from the parent
  65.  *            process.
  66.  *
  67.  *    External Functions:
  68.  *    -------------------
  69.  *    play_engine_thread
  70.  *            This is the routine that will be called
  71.  *            whenever the 'other_process' receives a
  72.  *            "run" command.  When it returns, the
  73.  *            'other_process' will go back into a wait
  74.  *            to be commanded to start again.
  75.  *
  76.  *    Global Functions:
  77.  *    -----------------
  78.  *    CreateSubProcess
  79.  *            This routine actually performs the sproc to
  80.  *            create the 'other_process'.  It also sets
  81.  *            up the semaphore arena and initializes
  82.  *            various flags.
  83.  *
  84.  *    StartSubProcess    Called by the parent process whenever it
  85.  *            wants to start the subprocess again.  This
  86.  *            routine does what is necessary to set/clear
  87.  *            semaphores in order to start the 'other_process'.
  88.  *
  89.  *    DestroySubProcess
  90.  *            This routine *must* be called when the
  91.  *            subprocess is no longer needed.  It returns
  92.  *            the semaphore arena to the system and kills
  93.  *            the subprocess.  If this is not done, the
  94.  *            subprocess doesn't quit (unless special code
  95.  *            is set up in the play_engine_thread to
  96.  *            find out that the parent has died).
  97.  *
  98.  * Conditional Compilation:
  99.  *    The following symbols will perform special compilation:
  100.  *
  101.  *    Define on compile command line:
  102.  *    -------------------------------
  103.  *    USE_SEMAPHORES    Compiles process so that it will use semaphores
  104.  *            to handshake between the two processes.  Other-
  105.  *            wise it uses the 'blockproc' functions.
  106.  *
  107.  *    DEBUG_SP    Add special debug prints and routines to debug
  108.  *            the subprocess activities.
  109.  *
  110.  *    DEBUG_PRIO    Add special debug prints to check priority stuff.
  111.  *
  112.  *    Defined in this source file:
  113.  *    ----------------------------
  114.  *    PARENT_PRI    The parent is also set up with non-degrading
  115.  *            priority.  This symbol should be set to the
  116.  *            desired priority.
  117.  *
  118.  *    USE_EXT_SEM    Use external semaphores rather than our own
  119.  *            arena.
  120.  *----------------------------------------------------------------------*/
  121.  
  122. /*----------------------------------------------------------------------
  123.  *  III   N   N   CCC   L     U   U  DDDD   EEEEE   SSS
  124.  *   I    NN  N  C   C  L     U   U  D   D  E      S   S
  125.  *   I    NN  N  C      L     U   U  D   D  E      S
  126.  *   I    N N N  C      L     U   U  D   D  EEE     SSS
  127.  *   I    N  NN  C      L     U   U  D   D  E          S
  128.  *   I    N  NN  C   C  L     U   U  D   D  E      S   S
  129.  *  III   N   N   CCC   LLLL   UUU   DDDD   EEEEE   SSS
  130.  *----------------------------------------------------------------------*/
  131.  
  132. #include <stdio.h>
  133. #include <stdlib.h>
  134. #include <unistd.h>
  135. #include <string.h>
  136. #include <errno.h>
  137. #include <signal.h>
  138. #include <sys/types.h>
  139. #include <sys/prctl.h>
  140.  
  141. #ifdef USE_SEMAPHORES
  142. #include <sys/ipc.h>
  143. #include <sys/sem.h>
  144. #endif
  145.  
  146. #include <sys/schedctl.h>
  147. #include <sys/resource.h>
  148.  
  149. /*------------------------------------------------------------------------
  150.  * DDDD   EEEEE  FFFFF   III   N   N  EEEEE   SSS
  151.  * D   D  E      F        I    NN  N  E      S   S
  152.  * D   D  E      F        I    NN  N  E      S
  153.  * D   D  EEE    FFF      I    N N N  EEE     SSS
  154.  * D   D  E      F        I    N  NN  E          S
  155.  * D   D  E      F        I    N  NN  E      S   S
  156.  * DDDD   EEEEE  F       III   N   N  EEEEE   SSS
  157.  *------------------------------------------------------------------------*/
  158.  
  159. /* #define PARENT_PRI    32        /* Parent non-degrading priority */
  160.  
  161. #ifdef USE_SEMAPHORES
  162. /* #define USE_EXT_SEM            /* Set for external semaphore */
  163.  
  164. #ifdef USE_EXT_SEM
  165. #define SEM_KEY        37        /* Semaphore key */
  166. #endif
  167.  
  168. /*----
  169.  * The following semaphores are defined.  Note that there is some
  170.  * redundancy between these semaphores and the static variables 'run'
  171.  * and 'running'.
  172.  *
  173.  * Semaphore        Purpose
  174.  * ---------        -------
  175.  * SEM_RUN        Used to block child process.  Child waits for
  176.  *            this semaphore to be cleared by the parent to run.
  177.  *            Right after being started, the child sets this
  178.  *            semaphore to 1 to indicate it has started.  It
  179.  *            is initially set to 1 by parent before creating
  180.  *            the child.  It is cleared in StartSubProcess.
  181.  *
  182.  * SEM_RUNNING        Used to indicate the state of the child.  It
  183.  *            is set to 1 by the child just prior to calling
  184.  *            play_engine_thread.  It is cleared prior to
  185.  *            the child blocking and set after the child is
  186.  *            unblocked.
  187.  *----*/
  188.  
  189. #define SEM_RUN        0
  190. #define SEM_RUNNING    1
  191. #define NUM_SEMS    4        /* Number of semaphores to get */
  192.  
  193. #define S_UREAD        00400
  194. #define S_UALTER    00200
  195. #define S_GREAD        00040
  196. #define S_GALTER    00020
  197. #define S_OREAD        00004
  198. #define S_OALTER    00002
  199. #endif
  200.  
  201. /*------------------------------------------------------------------------
  202.  * PPPP   RRRR    OOO   TTTTT   OOO   TTTTT  Y   Y  PPPP   EEEEE   SSS
  203.  * P   P  R   R  O   O    T    O   O    T    Y   Y  P   P  E      S   S
  204.  * P   P  R   R  O   O    T    O   O    T     Y Y   P   P  E      S
  205.  * PPPP   RRRR   O   O    T    O   O    T      Y    PPPP   EEE     SSS
  206.  * P      R R    O   O    T    O   O    T      Y    P      E          S
  207.  * P      R  R   O   O    T    O   O    T      Y    P      E      S   S
  208.  * P      R   R   OOO     T     OOO     T      Y    P      EEEEE   SSS
  209.  *------------------------------------------------------------------------*/
  210.  
  211. extern void play_engine_thread (void);
  212.  
  213. /*------------------------------------------------------------------------
  214.  * EEEEE  X   X  TTTTT  EEEEE  RRRR   N   N   AAA   L      SSS
  215.  * E      X   X    T    E      R   R  NN  N  A   A  L     S   S
  216.  * E       X X     T    E      R   R  NN  N  A   A  L     S
  217.  * EEE      X      T    EEE    RRRR   N N N  AAAAA  L      SSS
  218.  * E       X X     T    E      R R    N  NN  A   A  L         S
  219.  * E      X   X    T    E      R  R   N  NN  A   A  L     S   S
  220.  * EEEEE  X   X    T    EEEEE  R   R  N   N  A   A  LLLLL  SSS
  221.  *------------------------------------------------------------------------*/
  222.  
  223. extern int    ndPriority;
  224. extern int    ProcessPriority;
  225. extern int    PGPriority;
  226. extern int    UserPriority;
  227.  
  228. /*------------------------------------------------------------------------
  229.  * L       OOO    CCC    AAA   L       SSS
  230.  * L      O   O  C   C  A   A  L      S   S
  231.  * L      O   O  C      A   A  L      S
  232.  * L      O   O  C      AAAAA  L       SSS
  233.  * L      O   O  C      A   A  L          S
  234.  * L      O   O  C   C  A   A  L      S   S
  235.  * LLLLL   OOO    CCC   A   A  LLLLL   SSS
  236.  *------------------------------------------------------------------------*/
  237.  
  238. #ifdef USE_SEMAPHORES
  239. static key_t        semKey;
  240. static int        semaphoreID;
  241. static union semun    semArg;
  242. static struct semid_ds    semBuf[NUM_SEMS];
  243. static ushort        semArray[NUM_SEMS];
  244. static struct sembuf    semBuffs[NUM_SEMS];
  245. #endif
  246.  
  247. static pid_t        parentPID;
  248. static pid_t        childPID;
  249.  
  250. /*---
  251.  * run        Set by parent when subprocess is to run.  Cleared by
  252.  *        child when it is acknowledged and before running.
  253.  * running    Initially set by parent before creating subprocess.
  254.  *        Indicates state of child.  Cleared before child
  255.  *        blocks.  Set when child unblocks.
  256.  * priviledged    Set if we had priviledges when we started.
  257.  *----*/
  258.  
  259. static int        run;
  260. static int        running;
  261.  
  262. static int        priviledged;
  263.  
  264. #if defined(USE_SEMAPHORES) && defined(DEBUG_SP)
  265. /*----------------------------------------------------------------------
  266.  * ReadBuf        Read the semaphore buffer.
  267.  *----------------------------------------------------------------------*/
  268.  
  269. struct semid_ds *ReadBuf (void)
  270. {
  271.     static char            *funcname = "ReadBuf";
  272.  
  273.     union semun            arg;
  274.     static struct semid_ds    buf;
  275.  
  276.     arg.buf = &buf;
  277.     if (semctl (semaphoreID, 0, IPC_STAT, arg) < 0) {
  278.     fprintf (stderr, "%s: Problem reading the semaphore buffer.\n",
  279.          funcname);
  280.     fprintf (stderr, "   %s\n", strerror (oserror ()));
  281.     }
  282.  
  283.     return &buf;
  284. }
  285.  
  286. /*----------------------------------------------------------------------
  287.  * ReadSem        Read a semaphore value.
  288.  *----------------------------------------------------------------------*/
  289.  
  290. ushort ReadSem (int sem)
  291. {
  292.     static char            *funcname = "ReadSem";
  293.  
  294.     register ushort        val;
  295.  
  296.     if ((val = semctl (semaphoreID, sem, GETVAL)) < 0) {
  297.     fprintf (stderr, "%s: Problem reading semaphore value.\n", funcname);
  298.     fprintf (stderr, "   %s\n", strerror (oserror ()));
  299.     }
  300.  
  301.     return val;
  302. }
  303.  
  304. /*----------------------------------------------------------------------
  305.  * ReadSemPID        Read a semaphore value.
  306.  *----------------------------------------------------------------------*/
  307.  
  308. short ReadSemPID (int sem)
  309. {
  310.     static char            *funcname = "ReadSemPID";
  311.  
  312.     register short        val;
  313.  
  314.     if ((val = semctl (semaphoreID, sem, GETPID)) < 0) {
  315.     fprintf (stderr, "%s: Problem reading semaphore PID.\n", funcname);
  316.     fprintf (stderr, "   %s\n", strerror (oserror ()));
  317.     }
  318.  
  319.     return val;
  320. }
  321.  
  322. /*----------------------------------------------------------------------
  323.  * ReadSemncnt        Read a semaphore value.
  324.  *----------------------------------------------------------------------*/
  325.  
  326. short ReadSemncnt (int sem)
  327. {
  328.     static char            *funcname = "ReadSemncnt";
  329.  
  330.     register short        val;
  331.  
  332.     if ((val = semctl (semaphoreID, sem, GETNCNT)) < 0) {
  333.     fprintf (stderr, "%s: Problem reading semaphore Ncnt.\n", funcname);
  334.     fprintf (stderr, "   %s\n", strerror (oserror ()));
  335.     }
  336.  
  337.     return val;
  338. }
  339.  
  340. /*----------------------------------------------------------------------
  341.  * ReadSemzcnt        Read a semaphore value.
  342.  *----------------------------------------------------------------------*/
  343.  
  344. short ReadSemzcnt (int sem)
  345. {
  346.     static char            *funcname = "ReadSemzcnt";
  347.  
  348.     register short        val;
  349.  
  350.     if ((val = semctl (semaphoreID, sem, GETZCNT)) < 0) {
  351.     fprintf (stderr, "%s: Problem reading semaphore Zcnt.\n", funcname);
  352.     fprintf (stderr, "   %s\n", strerror (oserror ()));
  353.     }
  354.  
  355.     return val;
  356. }
  357. #endif
  358.  
  359. #ifdef USE_SEMAPHORES
  360. /*----------------------------------------------------------------------
  361.  * semOp        Perform a semaphore operation and wait.
  362.  *
  363.  * Description:
  364.  *    Takes as input the 'sembuf' structure array, as is normally
  365.  *    passed to the system function 'semop'
  366.  *----------------------------------------------------------------------*/
  367.  
  368. static void semOp (struct sembuf *sembufs, int nbufs)
  369. {
  370.     static char            *funcname = "semOp";
  371.     register int        errno = -1;
  372.  
  373.     while (errno) {
  374.     errno = 0;
  375.     if (semop (semaphoreID, sembufs, nbufs) < 0) {
  376.         errno = oserror ();
  377.  
  378.         fprintf (stderr, "%s: semop error.\n", funcname);
  379.         fprintf (stderr, "   %s\n", strerror (errno));
  380.         if (errno == EIDRM) {    /* Semaphores are gone */
  381.         exit (0);
  382.         }
  383.     }
  384.     }
  385. }
  386. #endif
  387.  
  388. /*----------------------------------------------------------------------
  389.  * other_process    Other process that will be run.
  390.  *----------------------------------------------------------------------*/
  391.  
  392. static void other_process (void *x)
  393. {
  394.     static char            *funcname = "other_process";
  395.     register uid_t        uid;
  396.     register int        i;
  397. #ifdef USE_SEMAPHORES
  398.     struct sembuf        semBuffs[NUM_SEMS];
  399. #endif
  400.  
  401.     childPID = getpid ();
  402.  
  403. #ifdef DEBUG_SP
  404.     fprintf (stderr, "%s: running with PID %d\n", funcname, childPID);
  405. #endif
  406.  
  407.     /*----
  408.      * Initialize all of our semaphore buffers to have the
  409.      * semaphore ID in them.  We need our own copy so we don't
  410.      * screw up the parent process.
  411.      *----*/
  412.  
  413.     for (i = 0; i < NUM_SEMS; i++)
  414.     {
  415.     semBuffs[i].sem_num = i;
  416.     semBuffs[i].sem_flg = 0;
  417.     }
  418.  
  419.     /*----
  420.      * If we are running with priveleges, take advantage of it.
  421.      *----*/
  422.  
  423.     if (geteuid () == 0) {
  424.     priviledged = 1;
  425.  
  426.     /*----
  427.      * Set up non-degrading priorities to the max.
  428.      *----*/
  429.  
  430.     if (schedctl (NDPRI, 0, ndPriority) < 0) {
  431.         fprintf (stderr, "%s: Unable to set non-degrading priority.\n",
  432.              funcname);
  433.         fprintf (stderr, "   %s\n", strerror (oserror ()));
  434.     }
  435.     else if (schedctl (SLICE, 0, CLK_TCK) < 0)
  436.     {
  437.         fprintf (stderr, "%s: Unable to set time slice.\n", funcname);
  438.         fprintf (stderr, "    %s\n", strerror (oserror ()));
  439.     }
  440.  
  441.     /*----
  442.      * Force this process to remain resident in memory at all times.
  443.      *----*/
  444.  
  445.     if (prctl (PR_RESIDENT) < 0) {
  446.         fprintf (stderr, "%s: Unable to force residency.\n", funcname);
  447.         fprintf (stderr, "   %s\n", strerror (oserror ()));
  448.     }
  449.  
  450.     /*----
  451.      * Set the process priority as high as possible.
  452.      *----*/
  453.  
  454.     if (setpriority (PRIO_PROCESS, 0, ProcessPriority) < 0) {
  455.         fprintf (stderr, "%s: Unable to set process priority.\n",
  456.              funcname);
  457.         fprintf (stderr, "   %s\n", strerror (oserror ()));
  458.     }
  459.  
  460.     /*----
  461.      * Set the process group priority as high as possible.
  462.      *----*/
  463.  
  464.     if (setpriority (PRIO_PGRP, 0, PGPriority) < 0) {
  465.         fprintf (stderr, "%s: Unable to set process group priority.\n",
  466.              funcname);
  467.         fprintf (stderr, "   %s\n", strerror (oserror ()));
  468.     }
  469.  
  470.     /*----
  471.      * Set the user priority as high as possible.
  472.      *----*/
  473.  
  474.     if (setpriority (PRIO_USER, 0, UserPriority) < 0) {
  475.         fprintf (stderr, "%s: Unable to set user priority.\n",
  476.              funcname);
  477.         fprintf (stderr, "   %s\n", strerror (oserror ()));
  478.     }
  479.     }
  480.  
  481.     /*----
  482.      * Since we are done with the privileged stuff, lower our
  483.      * privilege back to the user's privilege.  We don't want
  484.      * to mess something up by mistake.
  485.      *----*/
  486.  
  487.     uid = getuid ();
  488.     if (setreuid (uid, uid) < 0) {
  489.     fprintf (stderr, "%s: Unable to set UIDs.\n", funcname);
  490.     fprintf (stderr, "   %s\n", strerror (oserror ()));
  491.     }
  492.  
  493. #ifdef DEBUG_PRIO
  494.     fprintf (stderr, "%s: Running with the following priorities:\n",
  495.          funcname);
  496.     fprintf (stderr, "\tPRIO_PROCESS    %d\n",
  497.          getpriority (PRIO_PROCESS, 0));
  498.     fprintf (stderr, "\tPRIO_PGRP       %d\n",
  499.          getpriority (PRIO_PGRP, 0));
  500.     fprintf (stderr, "\tPRIO_USER       %d\n",
  501.          getpriority (PRIO_USER, 0));
  502. #endif
  503.  
  504.     /*====
  505.      * Top of subprocess loop
  506.      *====*/
  507.  
  508.     while (1) {
  509.  
  510. #ifdef DEBUG_SP
  511.     fprintf (stderr, "%s: Waiting for RUN\n", funcname);
  512. #endif
  513.  
  514.  
  515.         /*----
  516.          * Set our state to not running.
  517.          *----*/
  518.  
  519.     running = 0;
  520.  
  521.         /*----
  522.          * Wait for semaphore flag to become 0 to continue.
  523.          * Decrement the semaphore indicating we are running.
  524.          *----*/
  525.  
  526. #ifdef USE_SEMAPHORES
  527.     semBuffs[SEM_RUNNING].sem_op = -1;    /* Clear running */
  528.     semOp (&semBuffs[SEM_RUNNING], 1);
  529.     semBuffs[SEM_RUN].sem_op = 0;        /* Wait for semaphore */
  530.     semOp (&semBuffs[SEM_RUN], 1);
  531. #else
  532.     if (blockproc (childPID) < 0) {
  533.         fprintf (stderr, "%s: An error occurred blocking myself.\n",
  534.              funcname);
  535.         fprintf (stderr, "   %s\n", strerror (oserror ()));
  536.         exit (-1);
  537.     }
  538. #endif
  539.  
  540.         /*----
  541.          * Set our state to running.
  542.          * Clear the request to run.
  543.          * Increment the semaphore requesting us to run.
  544.          * Increment the semaphore indicating we are running.
  545.          *----*/
  546.  
  547. #ifdef USE_SEMAPHORES
  548.     semBuffs[SEM_RUN].sem_op = 1;
  549.     semBuffs[SEM_RUNNING].sem_op = 1;
  550.     semOp (&semBuffs[SEM_RUN], 2);
  551. #endif
  552.  
  553.     running = 1;
  554.     run = 0;
  555.  
  556. #ifdef DEBUG_SP
  557.     fprintf (stderr, "%s: Ok, I'm running.\n", funcname);
  558. #endif
  559.  
  560.         /*----
  561.          * Execute the play engine.
  562.          *----*/
  563.  
  564.     play_engine_thread ();
  565.     }
  566. }
  567.  
  568. /*------------------------------------------------------------------------
  569.  * WaitForSubProcess        Waits for subprocess to complete.
  570.  *------------------------------------------------------------------------*/
  571.  
  572. void WaitForSubProcess (void)
  573. {
  574.     static char        *funcname = "WaitForSubProcess";
  575.  
  576. #ifdef DEBUG_SP
  577.     fprintf (stderr, "%s: Waiting for child to stop running.\n", funcname);
  578. #endif
  579.  
  580.     while (running && !run)            /* If flag is set, then we */
  581.     sginap (1);                /*   shouldn't even check. */
  582.  
  583. #ifdef USE_SEMAPHORES
  584.     semBuffs[SEM_RUNNING].sem_op = 0;        /* Ok, now check if running */
  585.     semOp (&semBuffs[SEM_RUNNING], 1);
  586. #endif
  587. }
  588.  
  589. /*----------------------------------------------------------------------
  590.  * CreateSubProcess    Routine creates the subprocess and semaphores.
  591.  *----------------------------------------------------------------------*/
  592.  
  593. void CreateSubProcess (void)
  594. {
  595.     static char            *funcname = "CreateSubProcess";
  596.  
  597.     register uid_t        uid;
  598.     register int        i;
  599.  
  600.     /*----
  601.      * First step is to create a semaphore for us to use between
  602.      * processes.
  603.      * 1. Use ftok to key a key identifier to use.
  604.      * 2. Use semget to get a block of semaphores.
  605.      *----*/
  606.  
  607. #ifdef USE_SEMAPHORES
  608. #ifdef USE_EXT_SEM
  609.     semKey = ftok ("/usr", SEM_KEY);
  610.     semaphoreID = semget (semKey, NUM_SEMS, (IPC_CREAT |
  611.                          S_UREAD | S_UALTER | S_GREAD |
  612.                          S_GALTER));
  613. #else
  614.     semaphoreID = semget (IPC_PRIVATE, NUM_SEMS,
  615.               (S_UREAD | S_UALTER | S_GREAD | S_GALTER));
  616. #endif
  617.     if (semaphoreID < 0) {
  618.     fprintf (stderr, "%s: Unable to get semaphore ID.\n", funcname);
  619.     fprintf (stderr, "   %s\n", strerror (errno));
  620.     exit (0);
  621.     }
  622.  
  623.     /*----
  624.      * Be sure to make the owner of this semaphore the real UID.
  625.      *----*/
  626.  
  627.     uid = getuid ();
  628.     semArg.buf = semBuf;
  629.     if (semctl (semaphoreID, -1, IPC_STAT, semArg) < 0)
  630.     {
  631.     fprintf (stderr, "%s: Unable to get semaphore buffers.\n", funcname);
  632.     fprintf (stderr, "   %s\n", strerror (errno));
  633.     }
  634.     else
  635.     {
  636.     for (i = 0; i < NUM_SEMS; i++)
  637.         semBuf[i].sem_perm.uid = uid;
  638.     if (semctl (semaphoreID, -1, IPC_SET, semArg) < 0)
  639.     {
  640.         fprintf (stderr, "%s: Unable to set semaphore UIDs.\n", funcname);
  641.         fprintf (stderr, "   %s\n", strerror (errno));
  642.     }
  643.     }
  644.  
  645. #ifdef DEBUG_SP
  646.     fprintf (stderr, "%s: Received semaphore ID %d.\n", funcname, semaphoreID);
  647. #endif
  648.  
  649.     /*----
  650.      * Next, clear the semaphores.
  651.      *----*/
  652.  
  653.     memset (semArray, 0, sizeof (semArray));
  654.     semArg.array = semArray;
  655.     if (semctl (semaphoreID, -1, SETALL, semArg) < 0) {
  656.     fprintf (stderr, "%s: Unable to clear semaphores.\n", funcname);
  657.     fprintf (stderr, "   %s\n", strerror (errno));
  658.     exit (-1);
  659.     }
  660.  
  661.     /*----
  662.      * Initialize all of our semaphore buffers to have the
  663.      * semaphore ID in them.
  664.      *----*/
  665.  
  666.     for (i = 0; i < NUM_SEMS; i++)
  667.     {
  668.     semBuffs[i].sem_num = i;
  669.     semBuffs[i].sem_flg = 0;
  670.     }
  671.  
  672.     /*----
  673.      * Set the SEM_RUN semaphore to indicate that we DO NOT
  674.      * want the subprocess to run.
  675.      *----*/
  676.  
  677.     semBuffs[SEM_RUN].sem_op = 1;    /* Set to indicate "don't run" */
  678.     semBuffs[SEM_RUNNING].sem_op = 1;    /* Assume child is running */
  679.     semOp (&semBuffs[SEM_RUN], 2);
  680. #endif
  681.  
  682.     run = 0;                /* Flag says don't run */
  683.     running = 1;            /* Assume child is running */
  684.  
  685.     parentPID = getpid ();
  686.  
  687.     if (sproc (other_process, PR_SALL) < 0) {
  688.     fprintf (stderr, "%s: Unable to sproc other process.\n", funcname);
  689.     fprintf (stderr, "   %s\n", strerror (errno));
  690.     exit (-1);
  691.     }
  692.  
  693. #ifdef PARENT_PRI
  694.     /*----
  695.      * If we are running with priveleges, schedule the non-degrading
  696.      * priority so we are higher than window functions.
  697.      *----*/
  698.  
  699.     if (geteuid () == 0) {
  700.     if (schedctl (NDPRI, 0, PARENT_PRI) < 0) {
  701.         fprintf (stderr, "%s: Unable to set non-degrading priority.\n",
  702.              funcname);
  703.         fprintf (stderr, "   %s\n", strerror (oserror ()));
  704.     }
  705.     }
  706. #endif
  707.  
  708.     if (setreuid (uid, uid) < 0) {
  709.     fprintf (stderr, "%s: Unable to set UIDs.\n", funcname);
  710.     fprintf (stderr, "   %s\n", strerror (oserror ()));
  711.     }
  712.  
  713.     /*----
  714.      * Wait for child to block
  715.      *----*/
  716.  
  717.     WaitForSubProcess ();
  718. }
  719.  
  720. /*----------------------------------------------------------------------
  721.  * DestroySubProcess        Kills the subprocess and releases the
  722.  *                 semaphores.
  723.  *----------------------------------------------------------------------*/
  724.  
  725. void DestroySubProcess (void)
  726. {
  727.     static char            *funcname = "DestroySubProcess";
  728.  
  729.     if (kill (childPID, SIGKILL) < 0) {
  730.     fprintf (stderr, "%s: Unable to kill child process.\n", funcname);
  731.     fprintf (stderr, "   %s\n", strerror (oserror ()));
  732.     }
  733.  
  734. #ifdef USE_SEMAPHORES
  735.     if (semctl (semaphoreID, 0, IPC_RMID) < 0) {
  736.     fprintf (stderr, "%s: Unable to release semaphores.\n", funcname);
  737.     fprintf (stderr, "   %s\n", strerror (errno));
  738.     }
  739. #endif
  740. }
  741.  
  742. /*----------------------------------------------------------------------
  743.  * StartSubProcess    Routine for telling the subprocess that it is
  744.  *             to do something.
  745.  *----------------------------------------------------------------------*/
  746.  
  747. void StartSubProcess (void)
  748. {
  749.     static char            *funcname = "StartSubProcess";
  750. #ifdef USE_SEMAPHORES
  751.     register ushort        semval;
  752. #else
  753.     register int        errorNo;
  754. #endif
  755.  
  756.     /*----
  757.      * Check if child process is already running.  Error is so.
  758.      *----*/
  759.  
  760. #ifdef USE_SEMAPHORES
  761.     if ((semval = semctl (semaphoreID, SEM_RUNNING, GETVAL)) < 0) {
  762.     fprintf (stderr, "%s: Error getting SEM_RUNNING semaphore.\n",
  763.          funcname);
  764.     fprintf (stderr, "   %s\n", strerror (oserror ()));
  765.     DestroySubProcess ();
  766.     exit (-1);
  767.     }
  768.     if (semval || running) {
  769.     fprintf (stderr, "%s: Subprocess is still running.\n", funcname);
  770.     fprintf (stderr, "   semval = %d, running = %d\n", semval, running);
  771.     DestroySubProcess ();
  772.     exit (-1);
  773.     }
  774. #else
  775.     if (running)
  776.     {
  777.     fprintf (stderr, "%s: Subprocess is still running.\n", funcname);
  778.     DestroySubProcess ();
  779.     exit (-1);
  780.     }
  781. #endif
  782.  
  783.     /*----
  784.      * Set the flag indicating we want him to run.
  785.      * Decrement the semaphore to start the play engine.
  786.      * Then send it a signal to kick it.
  787.      *----*/
  788.  
  789.     run = 1;
  790.  
  791. #ifdef DEBUG_SP
  792.     fprintf (stderr, "%s: Starting subprocess.\n", funcname);
  793. #endif
  794.  
  795. #ifdef USE_SEMAPHORES
  796.     semBuffs[SEM_RUN].sem_op = -1;
  797.     semOp (&semBuffs[SEM_RUN], 1);
  798. #else
  799. #ifdef DEBUG_SP
  800.     fprintf (stderr, "%s: Unblocking process %d\n", funcname, childPID);
  801. #endif
  802.  
  803.     if (unblockproc (childPID) < 0) {
  804.     errorNo = oserror ();
  805.     if (errorNo == ESRCH) {
  806.         fprintf (stderr, "%s: The play engine has died for some reason.\n",
  807.              funcname);
  808.         fprintf (stderr, "   No further playing or recording can take\n");
  809.         fprintf (stderr, "   place.  It is recommended that you save\n");
  810.         fprintf (stderr, "   your work and exit.  You can restart and\n");
  811.         fprintf (stderr, "   try again.\n");
  812.     } else {
  813.         fprintf (stderr, "%s: Some kind of error occurred trying to\n",
  814.              funcname);
  815.         fprintf (stderr, "   restart the play engine.\n");
  816.         fprintf (stderr, "   %s\n", sys_errlist[errorNo]);
  817.     }
  818.     }
  819.  
  820. #ifdef DEBUG_SP
  821.     if (prctl (PR_ISBLOCKED, childPID))
  822.     fprintf (stderr, "%s: The child %d is still blocked.\n", funcname,
  823.          childPID);
  824.     else
  825.     fprintf (stderr, "%s: The child %d is unblocked.\n", funcname,
  826.          childPID);
  827. #endif
  828. #endif
  829.  
  830.     /*----
  831.      * Give the child a moment to get going.
  832.      *----*/
  833.  
  834.     sginap (1);
  835. }
  836.